package net.hn.hnms.biz.plan.vo.work;


import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import net.hn.hnms.biz.plan.enums.ShiftTypeEnum;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Data
@NoArgsConstructor
@Accessors(chain = true)
@ApiModel("自动排班-人员班次信息")
public class PersonShiftVo {

    private String id;

    private String name;

    private int minShifts; // 最小带班次数

    private int maxShifts; // 最大带班次数

    private List<ShiftVo> assignedShifts = new ArrayList<>();

    // 定义班次顺序，用于判断是否为连续班次
    private static final List<String> shiftOrder = Arrays.asList(ShiftTypeEnum.SHIFT_0.getName(), ShiftTypeEnum.SHIFT_8.getName(), ShiftTypeEnum.SHIFT_4.getName());

    public PersonShiftVo(String id, String name, int minShifts, int maxShifts) {
        this.id = id;
        this.name = name;
        this.minShifts = minShifts;
        this.maxShifts = maxShifts;
    }

    public boolean canAssign(ShiftVo shift) {
        // 检查最大带班次数限制
        if (getAssignedLeadShiftsCount() >= getMaxShifts() && "2".equals(shift.getDutyType())) {
            System.out.println("拒绝分配：" + this.name + " 达到最大带班次数");
            return false;
        }

        // 检查是否前一天是夜班带班,当天不能值班
        LocalDate previousDay = shift.getDate().minusDays(1);
        boolean isPreviousNightShift = getAllAssignedShifts().stream()
                .anyMatch(s -> s.getDate().isEqual(previousDay) && ShiftTypeEnum.SHIFT_4.getName().equals(s.getShiftType()) && "2".equals(s.getDutyType()));
        if (isPreviousNightShift && "1".equals(shift.getDutyType())) {
            System.out.println("拒绝分配：" + this.name + " 前一天有夜班带班");
            return false;
        }

        // 检查是否会导致连续班次
        if (isConsecutive(shift)) {
            System.out.println("拒绝分配：" + this.name + " 会导致连续班次");
            return false;
        }

        // 检查同一天不能值班又带班
        if (hasSameDayDuty(shift)) {
            System.out.println("拒绝分配：" + this.name + " 同一天已有任务");
            return false;
        }

        // 如果所有规则都通过，则允许分配
        return true;
    }

    private boolean isConsecutive(ShiftVo shift) {
        LocalDate proposedDate = shift.getDate();
        String proposedShiftType = shift.getShiftType();

        // 值班不能连续
        boolean hasDutyOnSameDay = getAllAssignedShifts().stream()
                .anyMatch(s -> s.getDate().equals(proposedDate.minusDays(1)) && "1".equals(s.getDutyType()));


        // 检查同一天内是否有多个带班班次
        boolean hasMultipleShiftsOnSameDay = getAllAssignedShifts().stream()
                .anyMatch(s ->
                        s.getDate().equals(proposedDate) && "2".equals(s.getDutyType()) &&
                                (shiftOrder.indexOf(s.getShiftType()) + 1 == shiftOrder.indexOf(proposedShiftType) ||
                                        shiftOrder.indexOf(s.getShiftType()) - 1 == shiftOrder.indexOf(proposedShiftType))
                );

        // 检查前一天的晚班和当天的早班是否为同一个领导
        boolean hasConsecutiveShifts = getAllAssignedShifts().stream()
                .anyMatch(s ->
                        (s.getDate().isEqual(proposedDate.minusDays(1)) && ShiftTypeEnum.SHIFT_4.getName().equals(s.getShiftType()) && "2".equals(s.getDutyType())) ||
                                (s.getDate().isEqual(proposedDate) && ShiftTypeEnum.SHIFT_0.getName().equals(s.getShiftType()) && "2".equals(s.getDutyType()))
                );
        return hasDutyOnSameDay || hasMultipleShiftsOnSameDay || hasConsecutiveShifts;
    }

    private boolean hasSameDayDuty(ShiftVo shift) {
        return assignedShifts.stream().anyMatch(s -> s.getDate().equals(shift.getDate()));
    }

    public void assignShift(ShiftVo shift) {
        assignedShifts.add(shift);
    }

    // 获取仅限于“带班”的班次数量
    public int getAssignedLeadShiftsCount() {
        return (int) assignedShifts.stream()
                .filter(s -> "2".equals(s.getDutyType()))
                .count();
    }


    // 获取所有分配的班次
    public List<ShiftVo> getAllAssignedShifts() {
        return Collections.unmodifiableList(assignedShifts);
    }

    public int getAllAssignedShiftsCount() {
        return assignedShifts.size();
    }

    public int getAssignedDutyCount() {
        return (int) assignedShifts.stream()
                .filter(s -> "1".equals(s.getDutyType()))
                .count();
    }
}
